﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Model
{

    /// <summary>
    /// 全局调度系统,基础单例组件建立/事件管理由该系统负责
    /// </summary>
    public class DispatcherSystem:System
    {

        /// <summary>
        /// 预装载指定程序集的System、Event
        /// </summary>
        /// <param name="dllType">该程序集的类别</param>
        /// <param name="assembly">程序集文件</param>
        public void AddDll(DllType dllType , Assembly assembly)
        {
            AssembliesComponent Asc = GameRoot.Scene.GetComponent<AssembliesComponent>();
            EventComponent Evc= GameRoot.Scene.GetComponent<EventComponent>();

            if (Asc.AllAssemblies.Contains(dllType))
            {
                Log.Error($"{dllType}同类程序集已经装载。");
                return;
            }
            // 对应dllType位存放该程序集
            Asc.AllAssemblies.Add(dllType);

            UnOrderMultiMap<Type, Type> tempAttribute = new UnOrderMultiMap<Type, Type>();
            // 获取当前程序集中所有包含自定义特性的类[特性基类，对应的类list]
            foreach (Type type in assembly.GetTypes())
            {
                object[] obj = type.GetCustomAttributes(typeof(BaseAttribute), false);
                if (obj.Length == 0)
                {
                    continue;
                }
                // 只取当前类的特性【过滤掉派生类的特性】
                BaseAttribute baseAttribute = (BaseAttribute)obj[0];
                // 将当前类的特性与当前类关联起来并存入字典
                tempAttribute.Add(baseAttribute.AttributeType, type);
                Asc.AllAttributes.Add(baseAttribute.AttributeType, type);
            }
            if (tempAttribute.ContainsKey(typeof(ObjectEventAttribute)))
            {
                //读取所有的EventAttribute特性的类列表
                foreach (Type type in tempAttribute[typeof(ObjectEventAttribute)])
                {
                    //获取当前类下所有的Event特性
                    object[] attrs = type.GetCustomAttributes(typeof(ObjectEventAttribute), false);
                    if (attrs.Length == 0)
                    {
                        continue;
                    }
                    //实例化该事件
                    object obj = Activator.CreateInstance(type);
                    IEvent iEvent = obj as IEvent;
                    if (iEvent == null)
                    {
                        Log.Error($"{type.Name}拥有事件特性，但未继承IEvent接口");
                        continue;
                    }
                    foreach(ObjectEventAttribute attr in attrs)
                    {
                        foreach(EventType a in attr.Types)
                        {
                            Evc.AllEvents.Add(a, new EventPackage(attr.Priority, iEvent.Handle));
                        }
                    }
                }
            }

            //添加所有带有System特性的类
            if (tempAttribute.ContainsKey(typeof(ObjectSystemAttribute)))
            {
                foreach(Type type in tempAttribute[typeof(ObjectSystemAttribute)])
                {
                    object[] attrs = type.GetCustomAttributes(typeof(ObjectSystemAttribute), false);
                    if (attrs.Length == 0)
                    {
                        continue;
                    }
                    //实例化该系统
                    object obj = Activator.CreateInstance(type);
                    System system = obj as System;
                    if (system == null)
                    {
                        return;
                    }
                    GameRoot.allSystems.Add(type, system);
                    //执行对应系统创建方法
                    system.Create();
                }
            }

        }

        /// <summary>
        /// 外部导入单个事件
        /// </summary>
        /// <param name="type">事件类型</param>
        /// <param name="action">事件委托</param>
        /// <param name="priority">优先级</param>
        public void RegisterEvent(EventType type,Action<int[],object[]>action,int priority)
        {
            EventComponent Evc = GameRoot.Scene.GetComponent<EventComponent>();
            Evc.AllEvents.Add(type, new EventPackage(priority, action));
        }
        /// <summary>
        /// 注销指定事件类别【销毁该类事件类别】
        /// </summary>
        /// <param name="type">事件类型</param>
        public void LogoutEvent(EventType type)
        {
            EventComponent Evc = GameRoot.Scene.GetComponent<EventComponent>();
            if (!Evc.AllEvents.ContainsKey(type))
            {
                Log.Error($"尝试移除一个未注册事件：{(EventType)type}");
                return;
            }
            Evc.AllEvents.Remove(type);
        }
        /// <summary>
        /// 移除指定事件
        /// </summary>
        /// <param name="action"></param>
        public void LogoutOneEvent(Action<int[], object[]> action)
        {
            EventComponent Evc = GameRoot.Scene.GetComponent<EventComponent>();
            Evc.AllEvents.Remove(x=>x.action==action);
        }
        /// <summary>
        /// 添加新组件【Component调用】
        /// </summary>
        /// <param name="component">组件</param>
        public void AddComponent(Component component)
        {
            // 组件加入全局组件列表
            GameRoot.allComponents.Add(component.InstId, component);

        }
        public void AddEntity(Entity entity)
        {
            GameRoot.allEntities.Add(entity.InstID,entity);
        }
        /// <summary>
        /// 移除指定组件【Component调用】
        /// </summary>
        /// <param name="instId">组件GID</param>
        public void RemoveComponent(long instId)
        {
            GameRoot.allComponents.Remove(instId);            
        }
        public void RemoveEntity(long instID)
        {
            if (GameRoot.allEntities.ContainsKey(instID))
            {
                GameRoot.allEntities[instID].Dispose();
                GameRoot.allEntities.Remove(instID);
            }
        }
        /// <summary>
        /// 执行指定事件组
        /// </summary>
        /// <param name="type">指定事件的事件类型</param>
        /// <param name="paramType">指定事件的事件参数</param>
        /// <param name="param">事件处理用的参数表</param>
        public void Run(EventType type,int[]paramType,params object[] param)
        {
            EventComponent Evc = GameRoot.Scene.GetComponent<EventComponent>();
            if (!Evc.AllEvents.ContainsKey(type))
            {
                Log.Error($"事件{type}在注册之前被调用");
                return;
            }
            //依次执行所有事件
            foreach (EventPackage iEv in Evc.AllEvents[type])
            {
                try
                {
                    iEv.action.Invoke(paramType,param);
                }
                catch (Exception e)
                {
                    Log.Error($"执行{type}时发生错误：{e}");
                }
            }
            ParamsHelper.ReturnObj(param);//将本次使用的缓存归还给缓存管理器
        }

        public override void Destory()
        {
            GameRoot.Scene.Dispose();
        }
        public override void Create()
        {
            GameRoot.Scene.AddComponent<EventComponent>();
            GameRoot.Scene.AddComponent<AssembliesComponent>();
        }
    }
}
